/*
 * Copyright (C) 2020 Beijing Yishu Technology Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.miqt.plugin.inject.hook;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 该Class是由 inject-com.miqt.plugin.inject.annotation.compiler 自动生成的，请不要随意更改！
 */
public class HookClassesConfig {
    private static final Map<String, TargetClass> AROUND_HOOK_CLASSES = new HashMap<>();

    private static final Map<String, TargetClass> SUPER_HOOK_CLASSES = new HashMap<>();

    private HookClassesConfig() {
    }

    public static void init(Class clazz) {
        try {
            List<Object[]> aroundHookTargets = (List<Object[]>) clazz.getDeclaredMethod("getAroundHookTargets").invoke(null);
            List<Object[]> superHookTargets = (List<Object[]>)  clazz.getDeclaredMethod("getSuperHookTargets").invoke(null);

            for (Object[] aroundHookTarget : aroundHookTargets) {
                putAroundHookMethod(
                        (String)aroundHookTarget[0],
                        (String)aroundHookTarget[1],
                        (String)aroundHookTarget[2],
                        (String)aroundHookTarget[3],
                        (String)aroundHookTarget[4],
                        (String)aroundHookTarget[5],
                        (boolean)aroundHookTarget[6]);
            }
            for (Object[] superHookTarget : superHookTargets) {
                putSuperHookMethod(
                        (String)superHookTarget[0],
                        (String)superHookTarget[1],
                        (String)superHookTarget[2],
                        (String)superHookTarget[3],
                        (String)superHookTarget[4],
                        (String)superHookTarget[5],
                        (boolean)superHookTarget[6]);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    public static void putAroundHookMethod(String targetClassName, String targetMethodName,
                                           String targetMethodDesc, String injectClassName, String injectMethodName,
                                           String injectMethodDesc, boolean isAfter) {
        putHookMethod(AROUND_HOOK_CLASSES, targetClassName, targetMethodName, targetMethodDesc, injectClassName, injectMethodName, injectMethodDesc, isAfter);
    }

    public static void putSuperHookMethod(String targetClassName, String targetMethodName,
                                          String targetMethodDesc, String injectClassName, String injectMethodName,
                                          String injectMethodDesc, boolean isAfter) {
    putHookMethod(SUPER_HOOK_CLASSES, targetClassName, targetMethodName, targetMethodDesc, injectClassName, injectMethodName, injectMethodDesc, isAfter);
  }

  private static void putHookMethod(Map<String, TargetClass> classMap, String targetClassName,
      String targetMethodName, String targetMethodDesc, String injectClassName,
      String injectMethodName, String injectMethodDesc, boolean isAfter) {
    TargetClass targetClass = classMap.get(targetClassName);
        if (targetClass == null) {
            targetClass = new TargetClass(targetClassName);
            classMap.put(targetClassName, targetClass);
        }
        TargetMethod targetMethod = targetClass.getTargetMethod(targetMethodName, targetMethodDesc);
        if (targetMethod == null) {
            targetMethod = new TargetMethod(targetMethodName, targetMethodDesc);
            targetClass.addTargetMethod(targetMethod);
        }
        targetMethod.addInjectMethod(new InjectMethod(injectClassName, injectMethodName, injectMethodDesc, isAfter));
  }

  public static Map<String, TargetClass> getAroundHookClasses() {
    return Collections.unmodifiableMap(AROUND_HOOK_CLASSES);
  }

  public static Map<String, TargetClass> getSuperHookClasses() {
    return Collections.unmodifiableMap(SUPER_HOOK_CLASSES);
  }
}
